home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / strtoul.c < prev    next >
C/C++ Source or Header  |  1991-07-01  |  3KB  |  107 lines

  1. /* original from norbert schelenkar's stdio */
  2. /* eff hacks    ++jrb */
  3. /* conversion to ansi spec -- mj */
  4. /* 
  5.  * Base can be anything between 2 and 36 or 0.
  6.  * If not NULL then resulting *endptr points to the first
  7.  * non-accepted character.
  8.  */
  9.  
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15.  
  16. /* macro to avoid most frequent long muls on a lowly 68k */
  17. #define _BASEMUL(B, SH, X) \
  18.     ((0 != SH) ? \
  19.        ((10 == (B)) ? ((((X) << (SH)) + (X)) << 1) : ((X) << (SH))) : \
  20.        ((X) * (B))) 
  21.  
  22. unsigned long int strtoul(nptr, endptr, base)
  23. register const char *nptr;
  24. char **endptr;
  25. int base;
  26. {
  27.   register short c;
  28.   unsigned long result = 0L;
  29.   unsigned long limit;
  30.   short negative = 0;
  31.   short overflow = -2;    /* if this stays negative then no
  32.              conversion was performed */
  33.   short digit;
  34.   int shift;
  35.  
  36.   if (endptr != NULL)
  37.       *endptr = (char *)nptr;
  38.  
  39.   while ((c = *nptr) && isspace(c))    /* skip leading white space */
  40.     nptr++;
  41.   if ((c = *nptr) == '+' || c == '-') {    /* handle signs */
  42.     negative = (c == '-');
  43.     nptr++;
  44.   }
  45.   if (base == 0) {            /* determine base if unknown */
  46.     if (*nptr == '0') {
  47.         base = 8;
  48.         nptr++;
  49.         if ((c = *nptr) == 'x' || c == 'X') {
  50.             base += base;
  51.             nptr++;
  52.         }
  53.     }
  54.     else
  55.             base = 10;
  56.   }
  57.   else
  58.   if (base == 16 && *nptr == '0') {    /* discard 0x/0X prefix if hex */
  59.     nptr++;
  60.     if ((c = *nptr == 'x') || c == 'X')
  61.         nptr++;
  62.   }
  63.   if (base < 2 || base > 36)
  64.       return result;
  65.  
  66.   limit = ULONG_MAX/(unsigned long)base;     /* ensure no overflow */
  67.   shift = 0;
  68.   switch (base) {
  69.       case 32: shift++;
  70.       case 16: shift++;
  71.       case 8: shift++;
  72.       case 4: case 10: shift++;
  73.       case 2: shift++;
  74.       default:;
  75.   }
  76.   
  77.   nptr--;                /* convert the number */
  78.   while (c = *++nptr) {
  79.     if (isdigit(c))
  80.         digit = c - '0';
  81.     else
  82.         digit = c - (isupper(c) ? 'A' : 'a') + 10;
  83.     if (digit < 0 || digit >= base)
  84.         break;
  85.     overflow &= 1;        /* valid digit - some conversion performed */
  86.     if (0 == (overflow &= 1)) {    /* valid digit
  87.                        - some conversion performed */
  88.         if ((result > limit) ||
  89.         (digit >
  90.          (ULONG_MAX - (result = _BASEMUL(base, shift, result))))) {
  91.         result = ULONG_MAX;
  92.         errno = ERANGE;
  93.         overflow = 1;
  94.         negative = 0;
  95.         }
  96.         else 
  97.         result += digit;
  98.     }
  99.   }
  100.   if (negative)                /* ANSI says we should do this! */
  101.     result = 0L - result;
  102.  
  103.   if ((endptr != NULL) && (overflow >= 0))     /* move *endptr if some */
  104.       *endptr = (char *) nptr;                  /* digits were accepted */
  105.   return result;
  106. }
  107.